﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace GoStats.Model
{
    public static class API
    {
        /* The cookie received by the website login, to be used in all next requests */
        private static Cookie cookie;

        /**
         * login function, it posts the username and password to the website 
         * exactly like if they were sent from a browser. It receives a
         * cookie and save it to the cookie field
         * 
         */
        public static void Clear(){
            cookie = null;
        }
        public static async Task<Boolean> login(String username, String password)
        {
            

            var httphandler = new HttpClientHandler()
            {
                UseCookies = true,
                AllowAutoRedirect = false,
                CookieContainer = new CookieContainer()
            };
            HttpClient http = new HttpClient(httphandler);
            FormUrlEncodedContent content = new FormUrlEncodedContent(new[] 
            {
                new KeyValuePair<string, string>("username", username),
                new KeyValuePair<string, string>("password", password),
                new KeyValuePair<string, string>("submit", "Sign in")
            });

            content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
            http.DefaultRequestHeaders.Add("Accept", "text/html, application/xml, */*; q=0.01");
            http.DefaultRequestHeaders.Add("Accept-Encoding", "gzip,deflate,sdch");
            http.DefaultRequestHeaders.Add("Accept-Language", "en-US;q=0.6,en;q=0.4"); //fr-FR,fr;q=0.8,

            http.DefaultRequestHeaders.Add("Referer", "http://gostats.com/");
            http.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36");

            HttpResponseMessage message = await http.PostAsync("http://gostats.com/login.xml", content);
            String result = await message.Content.ReadAsStringAsync();
            String s = result;

            /* 
             * I found that gostats.com returns this status code only when the login details are correct.
             * SO we can use this information to know if the login was successful.
             * Other websites may return HttpStatusCode.Found in all cases (successful and unsuccessful lofin),
             * in that case you need to either test by number of returned cookies (in httphandler.CookieContainer),
             * or by trying later to load a protected page
             */
            if (message.StatusCode != HttpStatusCode.Found)
                return false;
            var y = message.Headers;
            CookieContainer cookies = httphandler.CookieContainer;
            Uri uri = new Uri("http://www.gostats.com/");
            int i = cookies.GetCookies(uri).Count;
            IEnumerable<Cookie> responseCookies = cookies.GetCookies(uri).Cast<Cookie>();

            /* it is one cookie is the responseCookies anyway ... */
            foreach (Cookie c in responseCookies)
            {
                cookie = new Cookie(c.Name, c.Value);
            }
            return true;
        }
        /*
         * This method gets the websites list of the user
         */
        public static async Task<List<Site>> getSites()
        {

            String result = await NetworkAbstraction("http://gostats.com/my_sites.xml");
            if (result.Length == 0) return null;

            List<Site> sites = new List<Site>();
            HtmlAgilityPack.HtmlDocument dokuman = new HtmlAgilityPack.HtmlDocument();
            dokuman.LoadHtml(result);

            // finds the first <ul> html tag, where class="my_sites"
            HtmlAgilityPack.HtmlNode my_sites = dokuman.DocumentNode.Descendants("ul").FirstOrDefault(x => x.GetAttributeValue("class", "").Equals("my_sites"));
            // finds all <li> tags within the above <ul> tag, where class="site"
            List<HtmlAgilityPack.HtmlNode> HTMLsites = my_sites.Descendants("li").Where(x => x.GetAttributeValue("class", "").Equals("site")).ToList();
            // get one website details from each <li>
            //int i = 1;
            foreach (HtmlAgilityPack.HtmlNode HTMLsite in HTMLsites)
            {
                String title = HTMLsite.Descendants("a").FirstOrDefault().InnerText;
                String url = HTMLsite.Descendants("a").FirstOrDefault(x => x.GetAttributeValue("href", "").Contains("summary.xml")).GetAttributeValue("href", "");
                Site s = new Site()
                {
                    Name = title,
                    //Name = "Site "+i, // for screenshots
                    Url = url
                };
                //i++;
                sites.Add(s);
            }
            return sites;
        }

        /* Network abstraction method for GET requests
         * it returns the page html content as String
         * 
         * Important !
         * There is a bug in WP8, cookies can work for only one subdomain even
         * if the website declares that the cookie is for all subdomains.
         * Example: websites specify the cookie's url as "http://.gostats.com"
         * to tell that it is for all subomaines such as www.gostats.com,
         * c1.gostats.com, c2.gostats.com, however HttpClient does not understand this.
         * 
         * Solution, for every page we visit, we recreate the cookie to that url specifically.
         */

        private static async Task<String> NetworkAbstraction(String url){
            CookieContainer cc = new CookieContainer();
            Uri uri2 = new Uri("http://gostats.com/");
            Uri uri3 = new Uri(url);
            cc.Add(uri2, cookie);
            cc.Add(uri3, cookie); //  <-- here we recreate the cookie for the specified url !
            var httphandler2 = new HttpClientHandler()
            {
                UseCookies = true,
                AllowAutoRedirect = false,
                CookieContainer = cc
            };

            HttpClient http = new HttpClient(httphandler2);
            HttpResponseMessage message = await http.GetAsync(url);
            String result = await (message).Content.ReadAsStringAsync();
            return result;
        }
        /*
         * This method gets the website statistiques
         */

        public static async Task<Boolean> details(Site site)
        {
            String result = await NetworkAbstraction(site.Url);
            if (result.Length == 0) return false;
            HtmlAgilityPack.HtmlDocument dokuman = new HtmlAgilityPack.HtmlDocument();
            dokuman.LoadHtml(result);

            // finds the html table where id="summary_table"
            HtmlAgilityPack.HtmlNode HTMLtable = dokuman.DocumentNode.Descendants("table").FirstOrDefault(x => x.GetAttributeValue("id", "").Equals("summary_table"));
            
            // finds all <tr> (lines) within the above html table
            List<HtmlAgilityPack.HtmlNode> HTMLtablelines = HTMLtable.Descendants("tr").ToList();

            /* Preparing the StatsSet fields in the class Site
             * TodayStats, YesterdayStats, SevenStats, ThirtyStats
             * and adding them to a List to fill them easily
             * 
             */
            List<StatsSet> stats = new List<StatsSet>();
            for(int i =0; i<4;i++){
                stats.Add(new StatsSet());
            }
            site.TodayStats = stats.ElementAt(0);
            site.YesterdayStats = stats.ElementAt(1);
            site.SevenStats = stats.ElementAt(2);
            site.ThirtyStats = stats.ElementAt(3);

            // the html column corresponding to each StatsSet
            List<int> htmlColomnsToRead = new List<int>() { 0, 2, 3, 5 };

            HtmlAgilityPack.HtmlNode HTMLpageviews = HTMLtablelines.ElementAt(1);
            int statsIndex = 0;
            foreach(int col in htmlColomnsToRead){
                String statCount = HTMLpageviews.Descendants("td").ElementAt(col).InnerText;
                int statCountInt = Convert.ToInt32(statCount);
                stats.ElementAt(statsIndex).pageViews=statCountInt;
                statsIndex++;
            }

            HtmlAgilityPack.HtmlNode HTMLvisitors = HTMLtablelines.ElementAt(3);
            statsIndex = 0;
            foreach (int col in htmlColomnsToRead)
            {
                String statCount = HTMLvisitors.Descendants("td").ElementAt(col).InnerText;
                int statCountInt = Convert.ToInt32(statCount);
                stats.ElementAt(statsIndex).uniqueVisitors = statCountInt;
                statsIndex++;
            }

            /* The chart */
            HtmlAgilityPack.HtmlNode HTMLchart = dokuman.DocumentNode.Descendants("div").FirstOrDefault(x => x.GetAttributeValue("class", "").Equals("summary_center"));
            String chartUrl = HTMLchart.Descendants("img").FirstOrDefault().GetAttributeValue("src", "");
            site.ThirtyChart = chartUrl;


            return true;
        } 

    }
}
